<script setup lang="ts" name="GoodsSku">
import { GoodsInfo, Spec, SpecValue } from '@/types/goods'
import bwPowerSet from '@/utils/power-set'


// sku组件的基本使用：
// 1. (必须)传入 商品信息对象 => 拥有了启用禁用, 选择功能
// 2. (可选)传入 skuId       => 默认回显, 默认让一些规格选中
// 3. 当 全部规格 选完的时候, 就是确定了一个sku, 需要子传父, 将 skuId 传给父即可


const props = defineProps<{
  goods: GoodsInfo
  skuId?: string
}>()
// 把选择好的商品 id传给父组件
const emit = defineEmits<{
  (e: 'changeSku', skuId: string): void
}>()


// 修改按钮的选中状态
const changeSelected = (item: Spec, sub: SpecValue) => {
  // item 表示当前规格  sub 规格当中的某一项

  // 1.如果选中了 二次点击，取消选中
  // 2.如果没选中，让他选中，并且排他
  // 判断sub 身上的disabled属性
  if (sub.disabled) return

  if (sub.selected) {
    // 如果本身selected处于选中状态，那么点击之后就把选中状态切换为false
    sub.selected = false
  } else {
    // 把同级所有(包括sub)的全部取消选中
    item.values.forEach((v) => (v.selected = false))
    // 让sub选中
    sub.selected = true
  }

  // 一旦按钮被重新选择了, 按钮状态也会随之需要更新
  updateDisabledStatus()
  // （1）判断，是否所有可选规格，都选择了
  const selectedArr = getSelectedSpec().filter((item) => item)
  // console.log(selectedArr);

  if (selectedArr.length === props.goods.specs.length) {
    // 说明都选中了
    // (2) 说明都选中，将得到的数组，转成字符串，去pathMap字典中找到当前字符串对应的对象 中找对应skuId
    const key = selectedArr.join('★')// '蓝色+10cm+中国'
    //  
    const result = pathMap[key]
    const skuId = result[0]// 这个skuId，是result中的唯一值


    // 3. 子传父，给父组件
    emit('changeSku', skuId)
  } else {
    emit('changeSku', '')
  }
}

/**
 * 定义路径字典库
 */
const getPathMap = () => {
  const pathMap: {
    [key: string]: string[]
  } = {}
  // 1. 过滤掉库存为0的sku
  const skus = props.goods.skus.filter((item) => item.inventory > 0)
  // console.log(skus)
  // 2. 遍历有效的sku,获取sku的幂集
  skus.forEach((item) => {
    //[{name: xxx, valueNa me: xxxx}] .map (sub =>{name: xxx, valueName: xxxx}.valueName )
    // [ 蓝色, 20cm ,中国 ]
    const arr = item.specs.map((sub) => sub.valueName)
    // console.log(arr)
    // 3. 调用powerSet获取幂集
    const powerSet = bwPowerSet(arr) // [ 蓝色 ]、
    // console.log(powerSet) // [ [] [] []]
    // 4. 把这些powerSet合并到一个路径字典中
    // 遍历子集，将子集的数据 往pathMap中整理
    //  （1）如果筛选条件 不存在 新开一个属性 存
    //  （2）如果筛选条件 已存在 在已有属性值 累加
    powerSet.forEach((sub) => {
      const key = sub.join('★') // 蓝色★20cm
      // 5. 判断pathMap中有没有key
      if (key in pathMap) {
        // 6. 存在 就在key 后面带上id
        pathMap[key].push(item.id)
      } else {
        // 7. 不存在 直接新开一个属性，属性值，是一个有一项内容的数组
        pathMap[key] = [item.id] // pathMap[蓝色★20cm] = [ id ]
      }
    })
  })

  return pathMap
}



// 更新按钮的禁用状态
const updateDisabledStatus = () => {
  // 获取选中的规格
  const selectArr = getSelectedSpec()// ['','','日本']
  // 根据路径字典 => 更新所有的按钮spaceValue的状态
  // 外层按钮
  props.goods.specs.forEach((spec, index) => {
    spec.values.forEach((specValue) => {
      //  让当前这个按钮，sub.name(黑色)和selectArr进行组合
      //注意： 这边尝试组合 判断是否禁用时 需要拷贝一份原数组
      const tempArr = [...selectArr]
      tempArr[index] = specValue.name // ['黑色'，'','日本']
      // 得到组合后转成字符串的key '黑色'+'日本'
      const key = tempArr.filter((item) => item).join('★')
      if (specValue.name in pathMap) {
        // 当前规格的名字在pathMap存在，不禁用
        specValue.disabled = false
      } else {
        // 当前规格在pathMap找不到，禁用
        specValue.disabled = true
      }
    })
  })
}


// 获取当前的选中状态
const getSelectedSpec = () => {
  const arr: string[] = []
  props.goods.specs.forEach((item) => {
    const temp = item.values.find((sub) => sub.selected)
    arr.push(temp ? temp.name : '')
  })
  // console.log(arr)
  return arr
}

// 默认根据父传子，传递的skuID,进行回显，设置选中状态
const initSelectedSpec = () => {
  if (!props.skuId) return
  const sku = props.goods.skus.find((item) => item.id === props.skuId)

  if (!sku) return
  // 基于sku.specs 让按钮设置成选中状态
  props.goods.specs.forEach((spec, index) => {
    // find,三个按钮 其实只会有一个选中
    const text = sku.specs[index].valueName
    const specValue = spec.values.find((item) => item.name === text)

    specValue!.selected = true

  })
}





// 1. 获取路径字典
const pathMap = getPathMap()
// 2. 先按照skuId进行初始化, 将选中状态设置好
// 设置默认选中必须在默认禁用之前设置
initSelectedSpec()
// 3. 根据目前已经选中的项 => 更新禁用状态
updateDisabledStatus()



</script>
<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.name">
      <dt>{{ item.name }}</dt>
      <dd>
        <!-- 特点：不能在template 上使用v-if  template最终不会渲染 -->
        <template v-for="sub in item.values" :key="sub.name">
          <img :class="{ selected: sub.selected, disabled: sub.disabled }" :src="sub.picture" alt="" v-if="sub.picture"
            @click="changeSelected(item, sub)" />
          <span v-else @click="changeSelected(item, sub)" :class="{ selected: sub.selected, disabled: sub.disabled }">{{
            sub.name
          }}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>

<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  &.selected {
    border-color: @xtxColor;
  }

  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;

    dt {
      width: 50px;
      color: #999;
    }

    dd {
      flex: 1;
      color: #666;

      >img {
        width: 50px;
        height: 50px;
        margin-top: 5px;
        .sku-state-mixin ();
      }

      >span {
        display: inline-block;
        height: 30px;
        line-height: 30px;
        padding: 0 20px;
        margin-top: 5px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
